﻿#include "videowindow.h"
#include <QAction>
#include <QApplication>
#include <QDrag>
#include <QLayout>
#include <QLinearGradient>
#include <QMenu>
#include <QMimeData>
#include <QPainter>
#include <QPaintEvent>
#include <QToolButton>
#include <QStyleOption>
#include "characterset.h"
#include "chatroom.h"
#include "zoomvideowidget.h"

#define VIDEO_NAMEBAR_HEIGHT 20
#define VIDEO_SOUNDBAR_HEIGHT 2
#define VIDEO_BOTTOM_HEIGHT (VIDEO_NAMEBAR_HEIGHT + VIDEO_SOUNDBAR_HEIGHT)
#define NAME_ROLE Qt::UserRole+2

VideoWindow::VideoWindow(QWidget *parent) : QWidget(parent), id(0), uid(0), rotate(0), zoom(Q_NULLPTR), toolBar(new QWidget(this)), video_timer_count(-1), audio_timer_count(-1), volume_(-1)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    setMouseTracking(true);

    toolBar->hide();

    QHBoxLayout *layout = new QHBoxLayout;
    layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));

    auto* button = new QToolButton();
    button->setText(QObject::trECSUTF8("左转"));
    //button->setAutoRaise(true);
    connect(button, &QAbstractButton::clicked, this, &VideoWindow::anticlockwiseRotate);
    layout->addWidget(button);

    button = new QToolButton();
    button->setText(QObject::trECSUTF8("复原"));
    //button->setAutoRaise(true);
    connect(button, &QAbstractButton::clicked, this, &VideoWindow::resetRotate);
    layout->addWidget(button);

    button = new QToolButton();
    button->setText(QObject::trECSUTF8("右转"));
    //button->setAutoRaise(true);
    connect(button, &QAbstractButton::clicked, this, &VideoWindow::clockwiseRotate);
    layout->addWidget(button);

    layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));

    layout->setMargin(0);
    layout->setSpacing(0);
    toolBar->setLayout(layout);
    //toolBar->setStyleSheet(QLatin1String(".QWidget{background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0.5, y2:0, stop:0 rgba(170, 170, 255, 0), stop:1 rgba(170, 170, 255, 128));}"));
}

QSize VideoWindow::sizeHint() const
{
    QSize size = videoSize;
    if(size.isValid())
        size.rheight() += VIDEO_BOTTOM_HEIGHT;
    return size;
}

QSize VideoWindow::minimumSizeHint() const
{
    return QSize(1, VIDEO_BOTTOM_HEIGHT + 1);
}

bool VideoWindow::tryAcceptDrop(QDropEvent *eFromParent)
{
    if(videoRect.contains(mapFromParent(eFromParent->pos())))
    {
        if(eFromParent->type() == QEvent::Drop)
            eFromParent->acceptProposedAction();
        else
        {
            QRect rtToParent(mapToParent(videoRect.topLeft()), videoRect.size());
            ((QDragMoveEvent*)eFromParent)->accept(rtToParent);
        }
        return true;
    }
    return false;
}

bool VideoWindow::tryContextMenu(QContextMenuEvent *eFromParent, QWidget *grandParent)
{
    if(videoRect.united(bottomRect).contains(mapFromParent(eFromParent->pos())))
    {
        auto menu = new QMenu(this);
        menu->setAttribute(Qt::WA_DeleteOnClose);
        bool hasAction = false;

        if(auto chatWindow = qobject_cast<ChatRoom*>(grandParent))
            hasAction |= chatWindow->handle_video_contentMenu(menu, id, uid);

        if(hasAction)
            menu->popup(eFromParent->globalPos());
        else
            delete menu;
        return true;
    }
    return false;
}

bool VideoWindow::isOn() const
{
    return uid > 0;
}

void VideoWindow::setId(int micid, qint64 uid, const QString &name)
{
    if(micid == this->id && uid == this->uid)
        return;
    setToolBarVisible(false);
    resetRotate();
    if(micid != this->id)
    {
        this->id = micid;
        if(micid == 0 && zoom)
            zoom->close();
    }
    if(uid != this->uid)
    {
        if(!uid || this->uid > 0)
        {
            stopVideoTimer(!uid);
            stopAudioTimer();
        }
        else if(!this->uid)
            updateVideoRect();
        this->uid = uid;
        if(uid <= 0)
            this->uname.clear();
        else if(name.isEmpty())
            this->uname = QString::number(uid);
        else
            this->uname = name;
    }
    if(!zoom)
        update(bottomRect);
    else if(micid > 0)
    {
        zoom->setTitle();
        zoom->update();
        update();
    }
}

void VideoWindow::handleVideo(const QPixmap &pix)
{
    videoPixmap = pix;
    if(!pix.isNull())
    {
        QSize size = pix.size();
        if(!size.isEmpty() && videoSize != size)
            videoSize = size;
    }
    updateVideoRect();
}

void VideoWindow::handle_volume(int volume)
{
    int vo = qBound(0,qMax(volume_,volume),100);
    if(audio_timer_count<0)
    {
        if(vo != volume_)
        {
            volume_ = vo;
            //update(volumeRect);
        }
        audio_timer_count = 0;
    }
}

void VideoWindow::handle_timer_event()
{
    if(!isEnabled())
        return;
    if(video_timer_count>=0)
    {
        if(++video_timer_count>=SHRT_MAX)
            stopVideoTimer();
    }
    if(audio_timer_count>=0)
    {
        if(++audio_timer_count>5)
            stopAudioTimer();
    }
}

void VideoWindow::paintEvent(QPaintEvent *e)
{
    QPainter paint(this);

    const QRect& rt = e->rect();

    if(!videoRect.isNull() && rt.intersects(videoRect))
    {
        if(zoom)
        {
            //画空框
            paint.drawRect(videoRect.left(), videoRect.top(), videoRect.width() - 1 , videoRect.height() - 1);
        }
        else if(uid <= 0)
        {
            drawBackground(paint, false);
        }
        else
        {
            QSize paintSize = videoRect.size();
            QSize pixmapSize = videoPixmap.size();
            if(!pixmapSize.isEmpty()) {
                if(rotate % 2 == 1)
                    pixmapSize.transpose();
                pixmapSize = pixmapSize.scaled(paintSize, Qt::KeepAspectRatio);
            }
            if(pixmapSize.isEmpty())
            {
                drawBackground(paint, true);
            }
            else
            {
                QRect trueRect;
                if(pixmapSize != paintSize)
                {
                    trueRect.setRect((videoRect.width() - pixmapSize.width()) / 2 + videoRect.left(), (videoRect.height() - pixmapSize.height()) / 2 + videoRect.top(), pixmapSize.width(), pixmapSize.height());
                    paint.setRenderHint(QPainter::SmoothPixmapTransform);
                }
                else
                    trueRect = videoRect;

                QRect paintRect;
                switch (rotate) {
                case 1:
                    paint.translate(trueRect.left() + trueRect.width(), trueRect.top());
                    paint.rotate(90);
                    paintRect.setRect(0, 0, trueRect.height(), trueRect.width());
                    break;
                case 2:
                    paint.translate(trueRect.left() + trueRect.width(), trueRect.top() + trueRect.height());
                    paint.rotate(180);
                    paintRect.setRect(0, 0, trueRect.width(), trueRect.height());
                    break;
                case 3:
                    paint.translate(trueRect.left(), trueRect.top() + trueRect.height());
                    paint.rotate(270);
                    paintRect.setRect(0, 0, trueRect.height(), trueRect.width());
                    break;
                default:
                    paint.translate(trueRect.left(), trueRect.top());
                    paintRect.setRect(0, 0, trueRect.width(), trueRect.height());
                    break;
                }

                //画视频
                paint.drawPixmap(paintRect, videoPixmap);
                paint.resetMatrix();
            }
        }
    }
/*
    if(!volumeRect.isNull() && rt.intersects(volumeRect))
    {
        if(volume_ >= 0)
        {
            //画背景
            QLinearGradient gradient(0, 0, volumeRect.width() / 2, 0);
            gradient.setSpread(QGradient::ReflectSpread);
            gradient.setColorAt(0, Qt::transparent);
            gradient.setColorAt(1, "greenyellow");
            paint.fillRect(volumeRect, gradient);
            if(volume_ > 0)
            {
                //画音量条                
                gradient.setColorAt(1, Qt::red);
                if(volume_ >= 100)
                    paint.fillRect(volumeRect, gradient);
                else {
                    int width = volumeRect.width() * volume_ / 100;
                    int left = (volumeRect.width() - width) / 2 + volumeRect.x();
                    gradient.setStart(left, 0);
                    gradient.setFinalStop(left + width / 2, 0);
                    //在中间画
                    paint.fillRect(left, volumeRect.y(), width, volumeRect.height(), gradient);
                }
            }
        }
    }
*/
    if(!bottomRect.isNull() && rt.intersects(bottomRect))
    {
        if(id > 0)
        {
            /*
            //画背景
            QLinearGradient gradient(0, 0, bottomRect.width() / 2, 0);
            gradient.setSpread(QGradient::ReflectSpread);
            gradient.setColorAt(0, Qt::transparent);
            gradient.setColorAt(1, "#89CEF2");
            paint.fillRect(bottomRect, gradient);
            */
            //if(fixed)
            //    paint.fillRect(bottomRect, QBrush(Qt::yellow, Qt::DiagCrossPattern));
            //画名字
            if(!uname.isEmpty())
                paint.drawText(bottomRect, Qt::AlignCenter, uname);
        }
    }
}

void VideoWindow::resizeEvent(QResizeEvent *e)
{
    const QSize &size = e->size();
    if(size.height() < VIDEO_BOTTOM_HEIGHT)
    {
        videoRect = bottomRect =  QRect();
        return;
    }

    QRect paintRect = rect();

    videoRect.setRect(paintRect.left(), paintRect.top(), paintRect.width(), paintRect.height() - VIDEO_BOTTOM_HEIGHT);
    bottomRect.setRect(videoRect.left(), videoRect.bottom() + 1, videoRect.width(), VIDEO_NAMEBAR_HEIGHT);

    toolBar->setGeometry(videoRect.left(), videoRect.top(), videoRect.width(), toolBar->sizeHint().height());
}

void VideoWindow::enterEvent(QEvent *e)
{
    if(!zoom)
        setToolBarVisible(uid > 0 && videoRect.contains(((QEnterEvent*)e)->pos()));
    QWidget::enterEvent(e);
}

void VideoWindow::leaveEvent(QEvent *e)
{
    setToolBarVisible(false);
    QWidget::leaveEvent(e);
}

#define ID_ROLE Qt::UserRole
#define MIC_ROLE Qt::UserRole+1

void VideoWindow::mouseMoveEvent(QMouseEvent *event)
{
    if(!zoom)
        setToolBarVisible(uid > 0 && videoRect.contains(event->pos()));
    QWidget::mouseMoveEvent(event);
    if (!(event->buttons() & Qt::LeftButton) || id <= 0)
        return;
    //只有有对应视频线路的窗口可以拖动
    if ((event->pos() - dragStartPosition).manhattanLength() < QApplication::startDragDistance())
        return;

    QDrag *drag = new QDrag(this);
    QMimeData *mimeData = new QMimeData;
    QByteArray encoded;
    {
        QDataStream stream(&encoded, QIODevice::WriteOnly);
        int n = 0;
        stream << n << n;
        QMap<int, QVariant> roles;
        roles[Qt::DisplayRole] = QObject::trECSUTF8("视频")+QString::number(id)+':'+uname;
        roles[ID_ROLE] = uid;
        roles[MIC_ROLE] = id;
        if(uid > 0)
            roles[NAME_ROLE] = uname;
        stream << roles;
    }
    mimeData->setData(QLatin1String("application/x-qabstractitemmodeldatalist"), encoded);
    drag->setMimeData(mimeData);

    drag->exec(Qt::CopyAction);
}

void VideoWindow::mousePressEvent(QMouseEvent *event)
{
    QWidget::mousePressEvent(event);
    if (event->button() == Qt::LeftButton && id > 0)
    {
        //只有有对应视频线路的窗口可以拖动
        dragStartPosition = event->pos();
        event->accept();
    }
}

void VideoWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(!videoRect.contains(event->pos()))
        return;
    if(zoom)
    {
        zoom->close();
    }
    else if(id > 0 && !videoSize.isEmpty())
    {
        setToolBarVisible(false);
        ZoomVideoWidget &zoomWidget = getZoomVideo();
        zoomWidget.resize(videoSize);
        zoomWidget.setRotate(rotate);
        zoomWidget.show();
    }
}

void VideoWindow::setToolBarVisible(bool visible)
{
    toolBar->setVisible(visible);
}

void VideoWindow::clockwiseRotate()
{
    quint8 rotateValue = (rotate + 1) % 4;
    rotate = rotateValue;
    update(videoRect);
}

void VideoWindow::anticlockwiseRotate()
{
    quint8 rotateValue = (rotate + 3) % 4;
    rotate = rotateValue;
    update(videoRect);
}

void VideoWindow::resetRotate()
{
    if(rotate == 0)
        return;
    rotate = 0;
    update(videoRect);
}

void VideoWindow::slot_zoomVideo_destroyed()
{
    if(zoom)
    {
        rotate = zoom->getRotate();
        zoom = Q_NULLPTR;
        update(videoRect);
    }
}

void VideoWindow::stopVideoTimer(bool update)
{
    video_timer_count=-1;
    if(!videoPixmap.isNull())
    {
        videoPixmap = QPixmap();
        if(!update)
            updateVideoRect();
    }
    if(update)
        updateVideoRect();
}

void VideoWindow::stopAudioTimer()
{
    audio_timer_count=-1;
    if(volume_ >= 0)
    {
        volume_ = -1;
        //update(volumeRect);
    }
}

void VideoWindow::updateVideoRect()
{
    if(zoom)
        zoom->update();
    else
        update(videoRect);
}

void VideoWindow::drawBackground(QPainter &paint, bool on)
{
    //取VideoRect中心的正方形
    int square = qMin(videoRect.width(), videoRect.height());
    if(square <= 0)
        return;
    //画背景图片
    QStyle *style = QWidget::style();
    QStyleOption opt;
    opt.init(this);
    opt.rect.setRect((videoRect.width() - square) / 2 + videoRect.left(), (videoRect.height() - square) / 2 + videoRect.top(), square, square);
    if(on)
        opt.state |= QStyle::State_On;
    style->drawPrimitive(QStyle::PE_Widget, &opt, &paint, this);
}

ZoomVideoWidget &VideoWindow::getZoomVideo()
{
    if(!zoom)
    {
        zoom = new ZoomVideoWidget(this);
        connect(zoom, &ZoomVideoWidget::destroyed, this, &VideoWindow::slot_zoomVideo_destroyed);
        update(videoRect);
    }
    return *zoom;
}
